#include "stdafx.h"
#include "Resource.h"
#include "GamePlay.h"
#include "CommonDef.h"

HINSTANCE G_CURRENT_HINSTANCE;
HMENU G_CHESS_MENU;
HMENU G_CHESS_MENU_POP;
std::unique_ptr<GamePlay> game_play = nullptr;

HRESULT ChessRegisterClass(HINSTANCE);
HRESULT InitInstance(HINSTANCE, int);
LRESULT CALLBACK ChessWndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT SetClientSize(HWND, int, int);

int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE pre_instance, LPTSTR cmd_line, int cmd_show)
{
    UNREFERENCED_PARAMETER(pre_instance);
    UNREFERENCED_PARAMETER(cmd_line);

    ErrorLogger::Initialize();
    game_play.reset(new GamePlay);

    HRESULT hr = E_FAIL;
    if (FAILED(hr = ChessRegisterClass(instance)))
    {
        ErrorLogger::WriteLog(__FUNCTION__, "Failed to register class.");
        return 0;
    }

    if (FAILED(hr = InitInstance(instance, cmd_show)))
    {
        ErrorLogger::WriteLog(__FUNCTION__, "Failed to initialize instance.");
        return 0;
    }

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return static_cast<int>(msg.wParam);
}

HRESULT ChessRegisterClass(HINSTANCE instance)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style         = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc   = ChessWndProc;
    wcex.cbClsExtra    = 0;
    wcex.cbWndExtra    = 0;
    wcex.hInstance     = instance;
    wcex.hIcon         = LoadIcon(instance, IDI_APPLICATION);
    wcex.hCursor       = LoadCursor(instance, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName  = NULL;
    wcex.lpszClassName = GC_APPLICATION_NAME.c_str();
    wcex.hIconSm       = NULL;

    RegisterClassEx(&wcex);

    return S_OK;
}

HRESULT InitInstance(HINSTANCE instance, int cmd_show)
{
    G_CURRENT_HINSTANCE = instance;

    HWND hwnd = CreateWindow(GC_APPLICATION_NAME.c_str(), GC_APPLICATION_NAME.c_str(),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL);
    if (!hwnd)
    { // Not a pure pointer, can't use the Macro.
        return E_FAIL;
    }

    // Create menu
    G_CHESS_MENU = CreateMenu();
    G_CHESS_MENU_POP = CreateMenu();
    AppendMenu(G_CHESS_MENU_POP, MF_STRING, IDM_START,"Start Game");
    AppendMenu(G_CHESS_MENU_POP, MF_STRING, IDM_RESTART,"Restart Game");
    AppendMenu(G_CHESS_MENU_POP, MF_STRING, IDM_EXIT, "Exit");
    AppendMenu(G_CHESS_MENU, MF_POPUP, (unsigned int)G_CHESS_MENU_POP, "Menu");
    SetMenu(hwnd, G_CHESS_MENU);

    RETURN_AND_RECORD_ERROR_MESSAGE_IF_FAILED(SetClientSize(hwnd, 530, 538))

    ShowWindow(hwnd, cmd_show);
    UpdateWindow(hwnd);

    return S_OK;
}

HRESULT SetClientSize(HWND hwnd, int width, int height)
{
    if (!hwnd)
    {
        ErrorLogger::WriteLog(__FUNCTION__, "Failed to create window.");
        return E_FAIL;
    }

    RECT rect_window;
    RECT rect_client;
    RETURN_AND_RECORD_ERROR_MESSAGE_IF_FALSE(GetWindowRect(hwnd, &rect_window))
    RETURN_AND_RECORD_ERROR_MESSAGE_IF_FALSE(GetClientRect(hwnd, &rect_client))

    int temp_width = rect_window.right - rect_window.left -(rect_client.right - rect_client.left);
    int temp_height = rect_window.bottom - rect_window.top -(rect_client.bottom - rect_client.top);
    temp_width += width;
    temp_height += height;
    rect_window.right = temp_width;
    rect_window.bottom = temp_height;

    int screen_x = GetSystemMetrics(SM_CXSCREEN) / 2 - temp_width / 2;
    int screen_y = GetSystemMetrics(SM_CYSCREEN) / 2 - temp_height / 2;
    RETURN_AND_RECORD_ERROR_MESSAGE_IF_FALSE(
        MoveWindow(hwnd, screen_x, screen_y, rect_window.right, rect_window.bottom, false))

    return S_OK;
}

LRESULT CALLBACK ChessWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
    int wparam_id    = INVALID_INDEX;
    int wparam_event = INVALID_INDEX;

    switch (message)
    {
    case WM_COMMAND:
        wparam_id    = LOWORD(wparam);
        wparam_event = HIWORD(wparam);
        if (wparam_id == IDM_START)
        {
            game_play->StartGame(hwnd);
        }
        else if (wparam_id == IDM_RESTART)
        {
            game_play.reset(new GamePlay);
            game_play->StartGame(hwnd);

            RECT client_rect;
            GetClientRect(hwnd, &client_rect);
            InvalidateRect(hwnd, &client_rect, true);
        }
        else if (wparam_id == IDM_EXIT)
        {
            PostQuitMessage(0);
        }
        else
        {

        }
        break;
    case WM_PAINT:
        {
            BOOL is_start = FALSE;
            game_play->IsStart(is_start);
            if (is_start)
            {
                game_play->ControlsDrawing(hwnd);
            }
        }
        break;
    case WM_LBUTTONUP:
        {
            BOOL is_start = FALSE;
            game_play->IsStart(is_start);
            if (is_start)
            {
                BOOL is_select = FALSE;
                game_play->IsSelectChessPiece(is_select);
                if (!is_select)
                {
                    game_play->ControlsSelectPieces(LOWORD(lparam), HIWORD(lparam), hwnd);
                    PostMessage(hwnd, WM_PAINT, 0, 0);
                }
                else
                {
                    game_play->ControlsMovePieces(hwnd, LOWORD(lparam), HIWORD(lparam));

                    RECT client_rect;
                    GetClientRect(hwnd, &client_rect);
                    InvalidateRect(hwnd, &client_rect, true);
                }
            }
        }
        break;
    case WM_MOUSEMOVE:
        {
            BOOL is_start = FALSE;
            game_play->IsStart(is_start);
            if (is_start)
            {

            }
        }
        break;
    case WM_RBUTTONUP:
        {
            BOOL is_start = FALSE;
            game_play->IsStart(is_start);
            if (is_start)
            {
                BOOL is_select = FALSE;
                game_play->IsSelectChessPiece(is_select);
                if (is_select)
                {
                    game_play->SetNoSelectChessPiece();

                    RECT client_rect;
                    GetClientRect(hwnd, &client_rect);
                    InvalidateRect(hwnd, &client_rect, true);
                }
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, message, wparam, lparam);
    }

    return 0;
}